package com.young.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 日期处理工具类
 * 
 */
public class DateUtil {

	//public static final String defaultDatePattern = "yyyy-MM-dd HH:mm:ss.SSS";

	private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);


	/**
	 * 时间格式化模式枚举类
	 */
	public enum FormatPattern {
		DEFAULT("yyyy-MM-dd HH:mm:ss"),
		DEFAULT_DATE("yyyy-MM-dd"),
		DEFAULT_TIME("yyyy-MM-dd HH:mm:ss"),

		YYYY_MM_DD_HH_MI_SS_SSS("yyyy-MM-dd HH:mm:ss.SSS"),
		YYYY_MM_DD_HH_MI_SS("yyyy-MM-dd HH:mm:ss"),
		YYYY_MM_DD_HH_MI("yyyy-MM-dd HH:mm"),
		YYYY_MM_DD_HH("yyyy-MM-dd HH"),
		YYYY_MM_DD("yyyy-MM-dd"),
		YYYY_MM("yyyy-MM"),

		S_YYYY_MM_DD_HH_MI_SS_SSS("yyyy/MM/dd HH:mm:ss.SSS"),
		S_YYYY_MM_DD_HH_MI_SS("yyyy/MM/dd HH:mm:ss"),
		S_YYYY_MM_DD_HH_MI("yyyy/MM/dd HH:mm"),
		S_YYYY_MM_DD_HH("yyyy/MM/dd HH"),
		S_YYYY_MM_DD("yyyy/MM/dd"),
		S_YYYY_MM("yyyy/MM"),

		CN_YYYY_MM_DD_HH_MI_SS("yyyy年MM月dd日 HH时mm分ss秒"),
		CN_YYYY_MM_DD_HH_MI("yyyy年MM月dd日 HH时mm分"),
		CN_YYYY_MM_DD_HH("yyyy年MM月dd日 HH时"),
		CN_YYYY_MM_DD$HH_MI_SS("yyyy年MM月dd日HH时mm分ss秒"),
		CN_YYYY_MM_DD$HH_MI("yyyy年MM月dd日HH时mm分"),
		CN_YYYY_MM_DD$HH("yyyy年MM月dd日HH时"),
		CN_YYYY_MM_DD("yyyy年MM月dd日"),
		CN_YYYY_MM("yyyy年MM月"),

		N_YYYY$MM$DD$HH$MI$SS_SSS("yyyyMMddHHmmss.SSS"),
		N_YYYY$MM$DD$HH$MI$SS$SSS("yyyyMMddHHmmssSSS"),
		N_YYYY$MM$DD$HH$MI$SS("yyyyMMddHHmmss"),
		N_YYYY$MM$DD$HH$MI("yyyyMMddHHmm"),
		N_YYYY$MM$DD$HH("yyyyMMddHH"),
		N_YYYY$MM$DD("yyyyMMdd"),
		N_YYYY$MM("yyyyMM")
		;
		private String pattern;//格式化模式

		FormatPattern(String pattern){
			this.pattern = pattern;
		}

		public String getPattern() {
			return pattern;
		}

		public SimpleDateFormat getDateFormat() {
			return new SimpleDateFormat(pattern);
		}
	}

	/**
	 * 获取时间格式化模式
	 * @param dateStr
	 * @return
	 */
	public static FormatPattern getFormatPattern(String dateStr){
		if (dateStr == null) {
			return null;
		}
		FormatPattern result = null;
		if(dateStr.matches("\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}.\\d+")) {
			result = FormatPattern.YYYY_MM_DD_HH_MI_SS_SSS;
		} else if(dateStr.matches("\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}")) {
			result = FormatPattern.YYYY_MM_DD_HH_MI_SS;
		} else if(dateStr.matches("\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}")) {
			result = FormatPattern.YYYY_MM_DD_HH_MI;
		} else if(dateStr.matches("\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}")) {
			result = FormatPattern.YYYY_MM_DD_HH;
		} else if(dateStr.matches("\\d{4}-\\d{1,2}-\\d{1,2}")) {
			result = FormatPattern.YYYY_MM_DD;
		} else if(dateStr.matches("\\d{4}-\\d{1,2}")) {
			result = FormatPattern.YYYY_MM;
		} else if(dateStr.matches("\\d{4}/\\d{1,2}/\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}.\\d+")) {
			result = FormatPattern.S_YYYY_MM_DD_HH_MI_SS_SSS;
		} else if(dateStr.matches("\\d{4}/\\d{1,2}/\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}")) {
			result = FormatPattern.S_YYYY_MM_DD_HH_MI_SS;
		} else if(dateStr.matches("\\d{4}/\\d{1,2}/\\d{1,2} \\d{1,2}:\\d{1,2}")) {
			result = FormatPattern.S_YYYY_MM_DD_HH_MI;
		} else if(dateStr.matches("\\d{4}/\\d{1,2}/\\d{1,2} \\d{1,2}")) {
			result = FormatPattern.S_YYYY_MM_DD_HH;
		} else if(dateStr.matches("\\d{4}/\\d{1,2}/\\d{1,2}")) {
			result = FormatPattern.S_YYYY_MM_DD;
		} else if(dateStr.matches("\\d{4}/\\d{1,2}")) {
			result = FormatPattern.S_YYYY_MM;
		} else if(dateStr.matches("\\d{4}年\\d{1,2}月\\d{1,2}日\\d{1,2}时\\d{1,2}分\\d{1,2}秒")) {
			result = FormatPattern.CN_YYYY_MM_DD$HH_MI_SS;
		} else if(dateStr.matches("\\d{4}年\\d{1,2}月\\d{1,2}日\\d{1,2}时\\d{1,2}分")) {
			result = FormatPattern.CN_YYYY_MM_DD$HH_MI;
		} else if(dateStr.matches("\\d{4}年\\d{1,2}月\\d{1,2}日\\d{1,2}时")) {
			result = FormatPattern.CN_YYYY_MM_DD$HH;
		} else if(dateStr.matches("\\d{4}年\\d{1,2}月\\d{1,2}日")) {
			result = FormatPattern.CN_YYYY_MM_DD;
		} else if(dateStr.matches("\\d{4}年\\d{1,2}月")) {
			result = FormatPattern.CN_YYYY_MM;
		} else if(dateStr.matches("\\d{4}年\\d{1,2}月\\d{1,2}日 \\d{1,2}时\\d{1,2}分\\d{1,2}秒")) {
			result = FormatPattern.CN_YYYY_MM_DD_HH_MI_SS;
		} else if(dateStr.matches("\\d{4}年\\d{1,2}月\\d{1,2}日 \\d{1,2}时\\d{1,2}分")) {
			result = FormatPattern.CN_YYYY_MM_DD_HH_MI;
		} else if(dateStr.matches("\\d{4}年\\d{1,2}月\\d{1,2}日 \\d{1,2}时")) {
			result = FormatPattern.CN_YYYY_MM_DD_HH;
		} else if(dateStr.matches("\\d{14}.\\d+")) {
			result = FormatPattern.N_YYYY$MM$DD$HH$MI$SS_SSS;
		} else if(dateStr.matches("\\d{17}")) {
			result = FormatPattern.N_YYYY$MM$DD$HH$MI$SS$SSS;
		} else if(dateStr.matches("\\d{14}")) {
			result = FormatPattern.N_YYYY$MM$DD$HH$MI$SS;
		} else if(dateStr.matches("\\d{12}")) {
			result = FormatPattern.N_YYYY$MM$DD$HH$MI;
		} else if(dateStr.matches("\\d{10}")) {
			result = FormatPattern.N_YYYY$MM$DD$HH;
		} else if(dateStr.matches("\\d{8}")) {
			result = FormatPattern.N_YYYY$MM$DD;
		} else if(dateStr.matches("\\d{6}")) {
			result = FormatPattern.N_YYYY$MM;
		}
		return result;
	}

	/**
	 * 根据时间字符串获取对应的格式化模式
	 * @param dateStr 时间字符串
	 * @return
	 */
	public static String getFormatPatternAsString(String dateStr) {
		FormatPattern formatPattern = getFormatPattern(dateStr);
		return formatPattern != null ? formatPattern.getPattern() : null;
	}

	/**
	 * 根据时间字符串获取对应的时间格式化器
	 * @param dateStr
	 * @return
	 */
	private static SimpleDateFormat getFormatPatternAsSimpleDateFormat(String dateStr) {
		FormatPattern formatPattern = getFormatPattern(dateStr);
		return formatPattern != null ? formatPattern.getDateFormat() : null;
	}




	/**
	 * 将日期对象格式化成字符串
	 * 
	 * @param dateObj
	 *            日期对象 Date/Calendar
	 * @return String 格式化的日期表示
	 */
	public static String dateFormat(Object dateObj) {
		return dateFormat(dateObj, null);
	}

	/**
	 * 将日期对象格式化
	 * 
	 * @param dateObj
	 *            日期对象 Date/Calendar
	 * @param pattern
	 *            日期和时间的表示格式
	 * @return String 格式化的日期表示
	 */
	public static String dateFormat(Object dateObj, String pattern) {
		SimpleDateFormat sdf = (pattern == null) ? FormatPattern.DEFAULT.getDateFormat() : new SimpleDateFormat(pattern);
		if (dateObj == null) {
			return null;
		} else if (dateObj instanceof Calendar) { // Calendar
			Date date = ((Calendar) dateObj).getTime();
			return sdf.format(date);
		} else if (dateObj instanceof java.sql.Date) {
			Date date = new Date(((java.sql.Date) dateObj).getTime());
			return sdf.format(date);
		} else if (dateObj instanceof java.sql.Time) {
			Date date = new Date(((java.sql.Time) dateObj).getTime());
			return sdf.format(date);
		} else if (dateObj instanceof Timestamp) {
			Date date = new Date(((Timestamp) dateObj).getTime());
			return sdf.format(date);
		} else if (dateObj instanceof Date) {
			return sdf.format((Date) dateObj);
		} else {
			return null;
		}
	}

	/**
	 * 时间字符串转时间(自动识别格式化模式)
	 * @param dateStr 时间字符串
	 * @return
	 */
	public static Date toDate(String dateStr) {
		return toDate(dateStr, null);
	}
	/**
	 * 根据输入的日期字符串构造日期对象，并返回
	 * 
	 * @param dateStr
	 *            String 日期字符串，如：2005-01-01 12:00:00.000
	 * @param pattern
	 *            String 日期格式
	 * @return Date
	 */
	public static Date toDate(String dateStr, String pattern) {
		SimpleDateFormat sdf = (pattern != null) ? new SimpleDateFormat(pattern) : getFormatPatternAsSimpleDateFormat(dateStr);
		if (sdf == null) {
			sdf = FormatPattern.DEFAULT.getDateFormat();
			logger.warn("[时间格式化工具-字符串转时间] 匹配不到对应的格式化模式,字符串={},入参pattern={},设置使用默认的时间格式化器={}", dateStr, pattern, FormatPattern.DEFAULT.getPattern());
		}
		Date date = null;
		try {
			date = sdf.parse(dateStr);
		} catch (ParseException e) {
			logger.error("[时间格式化工具-字符串转时间] 字符串={},入参pattern={},实际使用格式化器={},异常:", dateStr, pattern, sdf.toPattern(), e);
		}
		return date;
	}

	public static void main(String[] args) {
		System.out.println(diffDate(toDate("2018-12-12 12"), toDate("2018-12-13 12")));
	}

	/**
	 * 计算两个日期之间相差的天数 if date1 > date2 返回正数 else if date1 < date2 返回负数 else 返回 0
	 * 
	 * @param date1
	 *            java.util.Date
	 * @param date2
	 *            java.util.Date
	 * @return int
	 */
	public static int diffDate(Date date1, Date date2) {
		GregorianCalendar gc1 = new GregorianCalendar();
		GregorianCalendar gc2 = new GregorianCalendar();
		gc1.setTime(date1);
		gc2.setTime(date2);
		return getDays(gc1, gc2);
	}

	/**
	 * 计算两个日期之间相差的小时 if date1 > date2 返回正数 else if date1 < date2 返回负数 else 返回 0
	 * 
	 * @param date1
	 *            java.util.Date
	 * @param date2
	 *            java.util.Date
	 * @return int
	 */
	public static long diffHour(Date date1, Date date2) {
		long time1 = date1.getTime();
		long time2 = date2.getTime();
		return (time1 - time2) / (1000 * 3600);
	}

	/**
	 * 计算相差多少天(向下取整,参数1小于参数2时返回负数)
	 * @param g1
	 * @param g2
	 * @return
	 */
	public static int getDays(GregorianCalendar g1, GregorianCalendar g2) {
		int elapsed = 0;
		GregorianCalendar gc1, gc2;

		if (g2.after(g1)) {
			gc2 = (GregorianCalendar) g2.clone();
			gc1 = (GregorianCalendar) g1.clone();
		} else {
			gc2 = (GregorianCalendar) g1.clone();
			gc1 = (GregorianCalendar) g2.clone();
		}

		gc1.clear(Calendar.MILLISECOND);
		gc1.clear(Calendar.SECOND);
		gc1.clear(Calendar.MINUTE);

		gc2.clear(Calendar.MILLISECOND);
		gc2.clear(Calendar.SECOND);
		gc2.clear(Calendar.MINUTE);

		while (gc1.before(gc2)) {
			gc1.add(Calendar.HOUR_OF_DAY, 1);
			elapsed++;
		}

		return g1.after(g2) ? elapsed / 24 : -elapsed / 24;
	}

	/**
	 * 相对与gc的一周的第一天
	 */
	public static GregorianCalendar getFirstWeekday(GregorianCalendar gc) {
		gc.add(Calendar.DAY_OF_MONTH, -(gc.get(Calendar.DAY_OF_WEEK) - 1));
		return gc;
	}

	/**
	 * 相对与gc的一月的第一天
	 */
	public static GregorianCalendar getFirstMonth(GregorianCalendar gc) {
		gc.set(Calendar.DAY_OF_MONTH, 1);
		return gc;
	}

	/**
	 * 相对与gc的一年的第一天
	 */
	public static GregorianCalendar getFirstYear(GregorianCalendar gc) {
		gc.set(Calendar.MONTH, 0);
		gc.set(Calendar.DAY_OF_MONTH, 1);
		return gc;
	}
	/** 
	  * 指定日期前几天或者后几天的日期 
	  * @param n 
	  * @return 
	  */  
	public static String afterNDay(Date date ,int n,String format) {
		SimpleDateFormat dateFormat = new SimpleDateFormat(format);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DATE, n);
		String sDate = dateFormat.format(calendar.getTime());
		return sDate;
	}

	/**
	 * 获取当前日期
	 * @return
	 */
	public static String getCurrentDay(){
		SimpleDateFormat sf = FormatPattern.DEFAULT_DATE.getDateFormat();//new SimpleDateFormat("yyyy-MM-dd");
		return sf.format(new Date());
	}

	/**
	 * 获取当天的日期对象
	 * @return
	 */
	public static Date getCurrentDayAsDate(){
		return toDate(getCurrentDay(), FormatPattern.DEFAULT_DATE.getPattern());
	}

	/**
	 * 获取当前时间
	 * @return
	 */
	public static String getCurrentTime(){
		SimpleDateFormat sf = FormatPattern.DEFAULT_TIME.getDateFormat();//new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return sf.format(new Date());
	}

	/**
	 * 获取当前年度
	 * @return
	 */
	public static int getCurrentYear() {
		Calendar c = Calendar.getInstance();
		return c.get(Calendar.YEAR);
	}

	/**
	 * 获取当前月份,比如当前是8月份,就返回8
	 * @return
	 */
	public static int getCurrentMonth(){
		Calendar c = Calendar.getInstance();
		int month = c.get(Calendar.MONTH);
		return month + 1;
	}
	//获取当前月最后一天日期
	public static String getCurrentMonthMaxDay(){
		Calendar c = Calendar.getInstance();
		String year = getCurrentYear() + "";
		String month = getCurrentMonth() + "";
		String day = getMaxDay(year,month) + 1 + "";
		return year + "-" + month + "-" + day;
	}
	// 获取当前季度
	public static int getCurrentQuarter() {
		Calendar c = Calendar.getInstance();
		int month = c.get(Calendar.MONTH);
		month = month + 1;
		int quarter = 0;
		if (month >= 1 && month <= 3) {
			quarter = 1;
		} else if (month >= 4 && month <= 6) {
			quarter = 2;
		} else if (month >= 7 && month <= 9) {
			quarter = 3;
		} else if (month >= 10 && month <= 12) {
			quarter = 4;
		}
		return quarter;
	}
	/**
	 * 获取指定年月的最大天数
	 * @param year 指定年
	 * @param month 指定月
	 * @return
	 */
	public static int getMaxDay(String year,String month){
		Calendar rightNow = Calendar.getInstance();
		rightNow.set(Calendar.YEAR,Integer.parseInt(year));
		rightNow.set(Calendar.MONTH,Integer.parseInt(month));
		int days = rightNow.getActualMaximum(Calendar.DAY_OF_MONTH);
		return days;
	}

	/**
	 * 获取指定年月的周末日期
	 * @param year 指定年
	 * @param month 指定月
	 * @return
	 */
	public static String getWeekEnd(String year,String month){

		StringBuffer sb = new StringBuffer();
		int dayNum = getMaxDay(year,month);
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.set(Calendar.YEAR,Integer.parseInt(year));
		calendar.set(Calendar.MONTH,Integer.parseInt(month)-1);
		calendar.set(Calendar.DATE,1);

		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
		for (int i = 0; i < dayNum; i++) {
			if(calendar.get(Calendar.DAY_OF_WEEK)==1||calendar.get(Calendar.DAY_OF_WEEK)==7){
				sb.append(sf.format(calendar.getTime())+",");
			}
			calendar.add(Calendar.DATE,1);
		}
		sb.deleteCharAt(sb.length()-1);
		return sb.toString();
	}
}
